package com.peas.platform.module.icims.expenditure.expenses.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.peas.platform.common.core.enums.BaseEnum;
import com.peas.platform.common.core.exception.BaseException;
import com.peas.platform.framework.mybatisplus.domain.BaseDomain;
import com.peas.platform.framework.mybatisplus.po.BasePo;
import com.peas.platform.framework.mybatisplus.service.BaseServiceImpl;
import com.peas.platform.module.icims.base.approve.component.ApproveCallback;
import com.peas.platform.module.icims.base.approve.dto.ApproveDto;
import com.peas.platform.module.icims.base.approve.dto.ApproveOrderNodeDto;
import com.peas.platform.module.icims.base.approve.enums.ApproveOrderBusinessType;
import com.peas.platform.module.icims.base.approve.enums.ApproveOrderOperType;
import com.peas.platform.module.icims.base.approve.service.ApproveOrderOperService;
import com.peas.platform.module.icims.base.approve.service.ApproveOrderService;
import com.peas.platform.module.icims.base.approve.service.ApproveService;
import com.peas.platform.module.icims.expenditure.basal.enums.ExpenditureAccountType;
import com.peas.platform.module.icims.expenditure.disbursement.dto.ExpenditureInternetbankItemDto;
import com.peas.platform.module.icims.expenditure.disbursement.dto.ExpenditureTreasuryItemDto;
import com.peas.platform.module.icims.expenditure.disbursement.service.ExpenditureInternetbankItemService;
import com.peas.platform.module.icims.expenditure.disbursement.service.ExpenditureTreasuryItemService;
import com.peas.platform.module.icims.expenditure.expenses.api.req.ExpenditureReimbursementReq;
import com.peas.platform.module.icims.expenditure.expenses.api.req.ReplenishExpenditureReimbursementReq;
import com.peas.platform.module.icims.expenditure.expenses.api.req.SaveExpenditureReimbursementReq;
import com.peas.platform.module.icims.expenditure.expenses.api.req.SubmitExpenditureReimbursementReq;
import com.peas.platform.module.icims.expenditure.expenses.controller.vo.*;
import com.peas.platform.module.icims.expenditure.expenses.domain.ExpenditureReimbursementDomain;
import com.peas.platform.module.icims.expenditure.expenses.dto.*;
import com.peas.platform.module.icims.expenditure.expenses.enums.*;
import com.peas.platform.module.icims.expenditure.expenses.service.*;
import com.peas.platform.module.icims.expenditure.kpis.service.ExpenditureKpiService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
public class ExpenditureReimbursementServiceImpl extends BaseServiceImpl<ExpenditureReimbursementDto> implements ExpenditureReimbursementService, ApproveCallback {

    @Resource
    private ExpenditureReimbursementDomain expenditureReimbursementDomain;
    @Resource
    private ExpenditureReimbursementTravelService expenditureReimbursementTravelService;
    @Resource
    private ExpenditureReimbursementContractService expenditureReimbursementContractService;
    @Resource
    private ExpenditureReimbursementMeetingService expenditureReimbursementMeetingService;
    @Resource
    private ExpenditureReimbursementTrainingService expenditureReimbursementTrainingService;
    @Resource
    private ExpenditureReimbursementTrafficService expenditureReimbursementTrafficService;
    @Resource
    private ExpenditureReimbursementAbroadService expenditureReimbursementAbroadService;
    @Resource
    private ExpenditureReimbursementOtherService expenditureReimbursementOtherService;
    @Resource
    private ExpenditureReimbursementItemFileService expenditureReimbursementItemFileService;
    @Resource
    private ExpenditureReimbursementPayService expenditureReimbursementPayService;
    @Resource
    private ExpenditureReimbursementPayeeService expenditureReimbursementPayeeService;
    @Resource
    private ExpenditureReimbursementFileService expenditureReimbursementFileService;
    @Resource
    private ApproveService approveService;
    @Resource
    private ApproveOrderService approveOrderService;
    @Resource
    private ApproveOrderOperService approveOrderOperService;
    @Resource
    private ExpenditureKpiService expenditureKpiService;
    @Resource
    private ExpenditureApplicationService expenditureApplicationService;
    @Resource
    private ExpenditureTreasuryItemService expenditureTreasuryItemService;
    @Resource
    private ExpenditureInternetbankItemService expenditureInternetbankItemService;

    @Override
    public BaseDomain<ExpenditureReimbursementDto, ? extends BasePo> getDomain() {
        return expenditureReimbursementDomain;
    }

    private List<ExpenditureReimbursementTravelDto> saveTravels(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementTravelVo> vos) {
        List<ExpenditureReimbursementTravelDto> travels = expenditureReimbursementTravelService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(travels)) {
            for (ExpenditureReimbursementTravelDto dto : travels) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementTravelService.removeBatchByList(travels);
        }
        List<ExpenditureReimbursementTravelDto> travelList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementTravelVo>) (value, index) -> {
                ExpenditureReimbursementTravelDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementTravelDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                travelList.add(dto);
            });
            expenditureReimbursementTravelService.saveBatch(travelList);
        }
        return travelList;
    }

    private List<ExpenditureReimbursementContractDto> saveContracts(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementContractVo> vos) {
        List<ExpenditureReimbursementContractDto> contracts = expenditureReimbursementContractService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(contracts)) {
            for (ExpenditureReimbursementContractDto dto : contracts) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementContractService.removeBatchByList(contracts);
        }
        List<ExpenditureReimbursementContractDto> contractList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementContractVo>) (value, index) -> {
                ExpenditureReimbursementContractDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementContractDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                contractList.add(dto);
            });
            expenditureReimbursementContractService.saveBatch(contractList);
        }
        return contractList;
    }

    private List<ExpenditureReimbursementMeetingDto> saveMeetings(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementMeetingVo> vos) {
        List<ExpenditureReimbursementMeetingDto> meetings = expenditureReimbursementMeetingService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(meetings)) {
            for (ExpenditureReimbursementMeetingDto dto : meetings) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementMeetingService.removeBatchByList(meetings);
        }
        List<ExpenditureReimbursementMeetingDto> meetingList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementMeetingVo>) (value, index) -> {
                ExpenditureReimbursementMeetingDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementMeetingDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                meetingList.add(dto);
            });
            expenditureReimbursementMeetingService.saveBatch(meetingList);
        }
        return meetingList;
    }

    private List<ExpenditureReimbursementTrainingDto> saveTrainings(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementTrainingVo> vos) {
        List<ExpenditureReimbursementTrainingDto> trainings = expenditureReimbursementTrainingService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(trainings)) {
            for (ExpenditureReimbursementTrainingDto dto : trainings) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementTrainingService.removeBatchByList(trainings);
        }
        List<ExpenditureReimbursementTrainingDto> trainingList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementTrainingVo>) (value, index) -> {
                ExpenditureReimbursementTrainingDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementTrainingDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                trainingList.add(dto);
            });
            expenditureReimbursementTrainingService.saveBatch(trainingList);
        }
        return trainingList;
    }

    private List<ExpenditureReimbursementTrafficDto> saveTraffics(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementTrafficVo> vos) {
        List<ExpenditureReimbursementTrafficDto> traffics = expenditureReimbursementTrafficService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(traffics)) {
            for (ExpenditureReimbursementTrafficDto dto : traffics) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementTrafficService.removeBatchByList(traffics);
        }
        List<ExpenditureReimbursementTrafficDto> trafficList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementTrafficVo>) (value, index) -> {
                ExpenditureReimbursementTrafficDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementTrafficDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                trafficList.add(dto);
            });
            expenditureReimbursementTrafficService.saveBatch(trafficList);
        }
        return trafficList;
    }

    private List<ExpenditureReimbursementAbroadDto> saveAbroads(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementAbroadVo> vos) {
        List<ExpenditureReimbursementAbroadDto> abroads = expenditureReimbursementAbroadService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(abroads)) {
            for (ExpenditureReimbursementAbroadDto dto : abroads) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementAbroadService.removeBatchByList(abroads);
        }
        List<ExpenditureReimbursementAbroadDto> abroadList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementAbroadVo>) (value, index) -> {
                ExpenditureReimbursementAbroadDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementAbroadDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                abroadList.add(dto);
            });
            expenditureReimbursementAbroadService.saveBatch(abroadList);
        }
        return abroadList;
    }

    private List<ExpenditureReimbursementOtherDto> saveOthers(List<Long> expenditureReimbursementItemIds, Long expenditureReimbursementId, List<ExpenditureReimbursementOtherVo> vos) {
        List<ExpenditureReimbursementOtherDto> others = expenditureReimbursementOtherService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        if (CollUtil.isNotEmpty(others)) {
            for (ExpenditureReimbursementOtherDto dto : others) {
                expenditureReimbursementItemIds.add(dto.getId());
            }
            expenditureReimbursementOtherService.removeBatchByList(others);
        }
        List<ExpenditureReimbursementOtherDto> otherList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementOtherVo>) (value, index) -> {
                ExpenditureReimbursementOtherDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementOtherDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                otherList.add(dto);
            });
            expenditureReimbursementOtherService.saveBatch(otherList);
        }
        return otherList;
    }

    private void savePays(Long expenditureReimbursementId, List<ExpenditureReimbursementPayVo> vos) {
        List<ExpenditureReimbursementPayDto> erpds1 = expenditureReimbursementPayService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        expenditureReimbursementPayService.removeBatchByList(erpds1);
        List<ExpenditureReimbursementPayDto> payList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementPayVo>) (value, index) -> {
                value.setExpenditureReimbursementId(expenditureReimbursementId);
                Assert.notNull(value.getExpenditureReimbursementId(), "报账单为空");
                Assert.notBlank(value.getPayType(), "支付方式不能为空");
                Assert.notBlank(value.getSettleType(), "结算方式不能为空");
                Assert.notBlank(value.getPayAccount(), "支付账户不能为空");
                Assert.notBlank(value.getPay(), "收付标识不能为空");
                Assert.notNull(value.getAmount(), "金额不能为空");
                ExpenditureReimbursementPayDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementPayDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                payList.add(dto);
            });
            expenditureReimbursementPayService.saveBatch(payList);
        }
    }

    private void savePayees(Long expenditureReimbursementId, List<ExpenditureReimbursementPayeeVo> vos) {
        List<ExpenditureReimbursementPayeeDto> erpds2 = expenditureReimbursementPayeeService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        expenditureReimbursementPayeeService.removeBatchByList(erpds2);
        List<ExpenditureReimbursementPayeeDto> payeeList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementPayeeVo>) (value, index) -> {
                value.setExpenditureReimbursementId(expenditureReimbursementId);
                Assert.notNull(value.getExpenditureReimbursementId(), "报账单为空");
                Assert.notBlank(value.getPayeeType(), "收款类型不能为空");
                ExpenditureReimbursementPayeeType payeeType = BaseEnum.key2Enum(ExpenditureReimbursementPayeeType.class, value.getPayeeType());
                Assert.notNull(payeeType, "收款类型取值不正确");
                switch (payeeType) {
                    case proceeds:
                        Assert.notNull(value.getExpenditureProceedsId(), "请选择收款单位");
                        Assert.notBlank(value.getProceedsCompany(), "收款单位名称不能为空");
                        Assert.notBlank(value.getProceedsBank(), "收款银行不能为空");
                        Assert.notBlank(value.getProceedsAccount(), "收款账号不能为空");
                        break;
                    case payee:
                        Assert.notNull(value.getExpenditureBusinessCardId(), "请选择公务持卡人");
                        Assert.notBlank(value.getBusinessCardName(), "公务卡持卡人不能为空");
                        Assert.notBlank(value.getBusinessCardBank(), "公务卡开户银行不能为空");
                        Assert.notBlank(value.getBusinessCardAccount(), "公务卡号不能为空");
                        break;
                }
                ExpenditureReimbursementPayeeDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementPayeeDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                payeeList.add(dto);
            });
            expenditureReimbursementPayeeService.saveBatch(payeeList);
        }
    }

    private void saveFiles(Long expenditureReimbursementId, List<ExpenditureReimbursementFileVo> vos) {
        List<ExpenditureReimbursementFileDto> erfds = expenditureReimbursementFileService.listByField("expenditureReimbursementId", expenditureReimbursementId);
        expenditureReimbursementFileService.removeBatchByList(erfds);
        List<ExpenditureReimbursementFileDto> fileList = new ArrayList<>();
        if (CollUtil.isNotEmpty(vos)) {
            CollUtil.forEach(vos, (CollUtil.Consumer<ExpenditureReimbursementFileVo>) (value, index) -> {
                ExpenditureReimbursementFileDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementFileDto.class);
                dto.setExpenditureReimbursementId(expenditureReimbursementId);
                fileList.add(dto);
            });
            expenditureReimbursementFileService.saveBatch(fileList);
        }
    }

    @Transactional
    @Override
    public ExpenditureReimbursementDto saveExpenditureReimbursement(SaveExpenditureReimbursementReq vo) {
        ExpenditureReimbursementDto ekd = BeanUtil.copyProperties(vo, ExpenditureReimbursementDto.class);
        if (StrUtil.isBlank(ekd.getState())) {
            ekd.setState(ExpenditureReimbursementState.save.getKey());
        }
        Assert.notNull(vo.getExpenditureKpiId(), "请选择指标单");
        // Assert.notNull(vo.getExpenditureApplicationId(), "请选择事前用款申请单");
        if (vo.getExpenditureApplicationId() != null) {
            ExpenditureApplicationDto ead = expenditureApplicationService.getById(vo.getExpenditureApplicationId());
            Assert.notNull(ead, "找不到事前用款申请单");
            Assert.equals(ead.getState(), ExpenditureApplicationState.pass.getKey(), "只有[" + ExpenditureApplicationState.pass.getValue() + "]状态的事前用款申请单才能创建报账单");
        }
        // 提交的时候才判断可用金额
        if (StrUtil.equals(ExpenditureReimbursementState.submit.getKey(), ekd.getState())) {
            Long expenditureKpiId = vo.getExpenditureKpiId();
            Assert.isTrue(expenditureKpiService.queryAvailableAmount(expenditureKpiId).compareTo(vo.getAmount()) >= 0, "报账金额不能超过指标单可用金额");
            if (StrUtil.isNotBlank(vo.getExpenditureEconomicId())) {
                Assert.isTrue(expenditureKpiService.queryAvailableAmount(expenditureKpiId, vo.getExpenditureEconomicId(), false).compareTo(BigDecimal.ZERO) >= 0, "报账金额不能超过指标单可用金额");
                Assert.isTrue(expenditureKpiService.queryAvailableAmount(expenditureKpiId, vo.getExpenditureEconomicId(), true).compareTo(vo.getAmount()) >= 0, "报账金额不能超过指标单可用金额");
            }
        }
        int result;
        if (vo.getId() != null) {
            ExpenditureReimbursementDto bean = this.getById(vo.getId());
            ExpenditureReimbursementState state = BaseEnum.key2Enum(ExpenditureReimbursementState.class, bean.getState());
            Assert.isTrue(ExpenditureReimbursementState.save == state || ExpenditureReimbursementState.revocation == state || ExpenditureReimbursementState.reject == state, "报账单[" + bean.getReimbursementCode() + "]的状态为[" + state.getKey() + "-" + state.getValue() + "]，不允许修改");
            result = this.updateById(ekd);
        } else {
            result = this.save(ekd);
        }
        Assert.isTrue(result > 0, "保存失败");
        List<Long> expenditureReimbursementItemIds = new ArrayList<>();
        // travels
        List<ExpenditureReimbursementTravelDto> travelList = this.saveTravels(expenditureReimbursementItemIds, ekd.getId(), vo.getTravels());
        // contracts
        List<ExpenditureReimbursementContractDto> contractList = this.saveContracts(expenditureReimbursementItemIds, ekd.getId(), vo.getContracts());
        // meetings
        List<ExpenditureReimbursementMeetingDto> meetingList = this.saveMeetings(expenditureReimbursementItemIds, ekd.getId(), vo.getMeetings());
        // trainings
        List<ExpenditureReimbursementTrainingDto> trainingList = this.saveTrainings(expenditureReimbursementItemIds, ekd.getId(), vo.getTrainings());
        // traffics
        List<ExpenditureReimbursementTrafficDto> trafficList = this.saveTraffics(expenditureReimbursementItemIds, ekd.getId(), vo.getTraffics());
        // abroads
        List<ExpenditureReimbursementAbroadDto> abroadList = this.saveAbroads(expenditureReimbursementItemIds, ekd.getId(), vo.getAbroads());
        // others
        List<ExpenditureReimbursementOtherDto> otherList = this.saveOthers(expenditureReimbursementItemIds, ekd.getId(), vo.getOthers());
        // itemFiles
        if (CollUtil.isNotEmpty(expenditureReimbursementItemIds)) {
            List<ExpenditureReimbursementItemFileDto> files = expenditureReimbursementItemFileService.listByField("expenditureReimbursementItemId", expenditureReimbursementItemIds);
            expenditureReimbursementItemFileService.removeBatchByList(files);
        }
        if (CollUtil.isNotEmpty(vo.getItemFiles())) {
            List<ExpenditureReimbursementItemFileDto> ekidList = new ArrayList<>();
            CollUtil.forEach(vo.getItemFiles(), (CollUtil.Consumer<ExpenditureReimbursementItemFileVo>) (value, index) -> {
                ExpenditureReimbursementItemFileDto dto = BeanUtil.copyProperties(value, ExpenditureReimbursementItemFileDto.class);
                Assert.notBlank(dto.getExpenditureReimbursementFeetype(), "报账单明细费用类型不能为空");
                ExpenditureReimbursementFeetype expenditureReimbursementFeetype = BaseEnum.key2Enum(ExpenditureReimbursementFeetype.class, dto.getExpenditureReimbursementFeetype());
                switch (expenditureReimbursementFeetype) {
                    case travel:
                        Assert.notEmpty(travelList, "找不到[" + ExpenditureReimbursementFeetype.travel.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(travelList.get(0).getId());
                        break;
                    case contract:
                        Assert.notEmpty(contractList, "找不到[" + ExpenditureReimbursementFeetype.contract.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(contractList.get(0).getId());
                        break;
                    case meeting:
                        Assert.notEmpty(meetingList, "找不到[" + ExpenditureReimbursementFeetype.meeting.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(meetingList.get(0).getId());
                        break;
                    case training:
                        Assert.notEmpty(trainingList, "找不到[" + ExpenditureReimbursementFeetype.training.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(trainingList.get(0).getId());
                        break;
                    case traffic:
                        Assert.notEmpty(trafficList, "找不到[" + ExpenditureReimbursementFeetype.traffic.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(trafficList.get(0).getId());
                        break;
                    case abroad:
                        Assert.notEmpty(abroadList, "找不到[" + ExpenditureReimbursementFeetype.abroad.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(abroadList.get(0).getId());
                        break;
                    case other:
                        Assert.notEmpty(otherList, "找不到[" + ExpenditureReimbursementFeetype.other.getValue() + "]报账明细");
                        dto.setExpenditureReimbursementItemId(otherList.get(0).getId());
                        break;
                }
                dto.setExpenditureReimbursementId(ekd.getId());
                String invoiceCode = dto.getInvoiceCode();
                List<ExpenditureReimbursementItemFileDto> list = expenditureReimbursementItemFileService.listByField("invoiceCode", invoiceCode);
                if (CollUtil.isNotEmpty(list)) {
                    throw new BaseException("发票附件[" + dto.getAttachmentName() + "]对应的发票代码[" + invoiceCode + "],在报销明细附件里已经存在");
                }
                ekidList.add(dto);
            });
            expenditureReimbursementItemFileService.saveBatch(ekidList);
        }
        // pays
        this.savePays(ekd.getId(), vo.getPays());
        // payees
        this.savePayees(ekd.getId(), vo.getPayees());
        // files
        this.saveFiles(ekd.getId(), vo.getFiles());
        return ekd;
    }

    @Transactional
    @Override
    public void submitExpenditureReimbursement(SubmitExpenditureReimbursementReq vo) {
        Assert.notNull(vo.getApproveId(), "请选择审批模版");
        SaveExpenditureReimbursementReq v = BeanUtil.copyProperties(vo, SaveExpenditureReimbursementReq.class);
        v.setState(ExpenditureReimbursementState.submit.getKey());
        v.setTravels(vo.getTravels());
        v.setContracts(vo.getContracts());
        v.setMeetings(vo.getMeetings());
        v.setTrainings(vo.getTrainings());
        v.setTraffics(vo.getTraffics());
        v.setAbroads(vo.getAbroads());
        v.setItemFiles(vo.getItemFiles());
        v.setPays(vo.getPays());
        v.setPayees(vo.getPayees());
        v.setFiles(vo.getFiles());
        ExpenditureReimbursementDto erd = this.saveExpenditureReimbursement(v);
        ApproveDto ad = approveService.getById(vo.getApproveId());
        ApproveOrderBusinessType approveOrderBusinessType = null;
        ExpenditureReimbursementType expenditureReimbursementType = BaseEnum.key2Enum(ExpenditureReimbursementType.class, erd.getReimbursementType());
        switch (expenditureReimbursementType) {
            case normal:
                approveOrderBusinessType = ApproveOrderBusinessType.expenditureReimbursement;
                break;
            case other:
                approveOrderBusinessType = ApproveOrderBusinessType.expenditureReimbursementOther;
                break;
        }
        approveOrderService.createApproveOrder(ad, BeanUtil.copyToList(vo.getApproveNodes(), ApproveOrderNodeDto.class), approveOrderBusinessType, erd.getId(), erd.getReimbursementCode(), null, this.getClass());
    }

    @Transactional
    @Override
    public void replenishExpenditureReimbursement(ReplenishExpenditureReimbursementReq vo) {
        ExpenditureReimbursementDto ekd = this.getById(vo.getId());
        // pays
        Assert.notEmpty(vo.getPays(), "请录入支出信息");
        this.savePays(ekd.getId(), vo.getPays());
        // payees
        Assert.notEmpty(vo.getPayees(), "请录入收款信息");
        this.savePayees(ekd.getId(), vo.getPayees());
        approveOrderOperService.saveApproveOrderOper(ApproveOrderOperType.replenish, null, null, null, null, null, ApproveOrderBusinessType.expenditureReimbursement, ekd.getId());
    }

    @Transactional
    @Override
    public void revocationExpenditureReimbursement(Long id) {
        ExpenditureReimbursementDto dto = this.getById(id);
        Assert.notNull(dto, "找不到报账单");
        dto.setState(ExpenditureReimbursementState.revocation.getKey());
        this.updateById(dto);
        approveOrderService.revocationApproveOrder(ApproveOrderBusinessType.expenditureReimbursement, id);
    }

    @Transactional
    @Override
    public void receiptExpenditureReimbursement(Long id) {
        ExpenditureReimbursementDto ekd = this.getById(id);
        Assert.notNull(ekd, "找不到报账单");
        Assert.equals(ExpenditureReimbursementState.pass.getKey(), ekd.getState(), "只有[{}]状态的报账单才能确认收单", ExpenditureReimbursementState.pass.getValue());
        ekd.setState(ExpenditureReimbursementState.complete.getKey());
        int result = this.updateById(ekd);
        Assert.isTrue(result > 0, "保存失败");
        approveOrderOperService.saveApproveOrderOper(ApproveOrderOperType.receipt, null, null, null, null, null, ApproveOrderBusinessType.expenditureReimbursement, ekd.getId());
    }

    @Override
    public Page<ExpenditureReimbursementDto> queryExpenditureReimbursement(Page<ExpenditureReimbursementDto> pager, ExpenditureReimbursementReq req, ExpenditureAccountType accountType) {
        return expenditureReimbursementDomain.queryExpenditureReimbursement(pager, req, accountType);
    }

    @Transactional
    @Override
    public void refreshExpenditureReimbursement(List<Long> expenditureReimbursementIds) {
        List<ExpenditureReimbursementDto> erds = this.listByIds(expenditureReimbursementIds);
        erds.forEach(value -> {
            BigDecimal total = BigDecimal.ZERO;
            // 关联的国库支付令
            List<ExpenditureTreasuryItemDto> list1 = expenditureTreasuryItemService.listByField("expenditureReimbursementId", value.getId());
            BigDecimal total1 = list1.stream().filter(v -> v.getExpenditureReimbursementId().equals(value.getId())).map(expenditureTreasuryItemDto -> NumberUtil.nullToZero(expenditureTreasuryItemDto.getAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
            total = total.add(total1);
            // 关联的网银支付
            List<ExpenditureInternetbankItemDto> list2 = expenditureInternetbankItemService.listByField("expenditureReimbursementId", value.getId());
            BigDecimal total2 = list2.stream().filter(v -> v.getExpenditureReimbursementId().equals(value.getId())).map(ExpenditureInternetbankItemDto -> NumberUtil.nullToZero(ExpenditureInternetbankItemDto.getAmount())).reduce(BigDecimal.ZERO, BigDecimal::add);
            total = total.add(total2);
            // 累计
            value.setPayedAmount(total);
            Assert.isTrue(value.getPayedAmount().compareTo(value.getAmount()) <= 0, "报账单[{}]付款金额[{}]超过了[{}]", value.getReimbursementCode(), value.getPayedAmount(), value.getAmount());
            if (StrUtil.equals(ExpenditureReimbursementState.complete.getKey(), value.getState())) {
                value.setState(ExpenditureReimbursementState.paying.getKey());
            }
            if (value.getAmount().equals(value.getPayedAmount())) {
                value.setState(ExpenditureReimbursementState.confirm.getKey());
            }
            if (value.getPayedAmount().equals(BigDecimal.ZERO)) {
                value.setState(ExpenditureReimbursementState.complete.getKey());
            }
            this.updateById(value);
        });
    }

    @Transactional
    @Override
    public void callbackAfterApprove(Long businessId, boolean isPass, boolean isFinalPass) {
        if (businessId == null)
            return;
        if (isPass) {
            if (isFinalPass) {
                ExpenditureReimbursementDto erd = this.getById(businessId);
                erd.setState(ExpenditureReimbursementState.pass.getKey());
                this.updateById(erd);
                // 回写申请单状态
                if (erd.getExpenditureApplicationId() != null) {
                    ExpenditureApplicationDto ead = expenditureApplicationService.getById(erd.getExpenditureApplicationId());
                    BigDecimal total = expenditureApplicationService.getTotalReimbursementAmount(erd.getExpenditureApplicationId());
                    if (NumberUtil.equals(ead.getAmount(), total)) {
                        ead.setState(ExpenditureApplicationState.complete.getKey());
                        expenditureApplicationService.updateById(ead);
                    }
                }
            }
        } else {
            ExpenditureReimbursementDto erd = this.getById(businessId);
            erd.setState(ExpenditureReimbursementState.reject.getKey());
            this.updateById(erd);
        }
    }
}
